//BlockQueue.hpp
#pragma once

#include<iostream>
#include<string>
#include<queue>
#include<pthread.h>

const static int defaultcap=5;

template<typename T>
class BlockQueue
{
private:
    bool isFull()
    {
        return _block_queue.size()==_max_cap;
    }
    
    bool isEmpty()
    {
        return _block_queue.empty();
    }

public:
    BlockQueue(int cap= defaultcap):_max_cap(cap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_P_cond,nullptr);
        pthread_cond_init(&_C_cond,nullptr);
    }
    void Pop(T *out)
    {
        pthread_mutex_lock(&_mutex);

        while(isEmpty())
        {
            pthread_cond_wait(&_C_cond,&_mutex);
        }

        *out=_block_queue.front();
        _block_queue.pop();

        pthread_mutex_unlock(&_mutex);

        pthread_cond_signal(&_P_cond);  //唤醒生产者
    }
    void Equeue(const T &in)
    {
        pthread_mutex_lock(&_mutex);

        while(isFull()) //阻塞队列满
        {
            //满了生产者不能再生产，必须等待
            pthread_cond_wait(&_P_cond,&_mutex); //被调用的时候，除了让自己继续排队等待，还会释放自己传递的锁
            //函数返回时，会返回在临界区，必须先参与锁的竞争，重新加上锁，该函数才会返回，依然是持有锁的状态

        }
        
        //阻塞队列未满或者被唤醒
        _block_queue.push(in);  //生产数据到阻塞队列
        
        pthread_mutex_unlock(&_mutex);

        pthread_cond_signal(&_C_cond);  //唤醒消费者
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_P_cond);
        pthread_cond_destroy(&_C_cond);
    }

private:
    std::queue<T> _block_queue;  //临界资源
    int _max_cap;
    pthread_mutex_t _mutex;
    pthread_cond_t _P_cond;  //生产者条件变量
    pthread_cond_t _C_cond;  //消费者条件变量
};